#include "EffectTechnique.h"
#include "XML\XMLTreeNode.h"
#include "Effect.h"
#include "RenderManager.h"
#include "EffectManager.h"
#include "Matrix\Matrix44.h"
#include <assert.h>

#if defined (_DEBUG)
#include "Memory/MemLeaks.h"
#endif

//-------------------------------------------------
CEffectTechnique::CEffectTechnique(CXMLTreeNode& _node)
	: m_pTechnique(NULL)
{
	m_sTechniqueName = _node.GetPszProperty("name", "");

	std::string l_sEffectName = _node.GetPszProperty("effect", "");
	m_pEffect = RENDER_MANAGER->GetEffectManager()->GetEffect(l_sEffectName);

	m_bUseWorldMatrix				= _node.GetBoolProperty("use_world_matrix", false, false);
	m_bUseViewMatrix				= _node.GetBoolProperty("use_view_matrix", false, false);
	m_bUse2DViewMatrix				= _node.GetBoolProperty("use_2d_view_matrix", false, false);
	m_bUseProjectionMatrix			= _node.GetBoolProperty("use_projection_matrix", false, false);
	m_bUseOrthographicMatrix		= _node.GetBoolProperty("use_orthographic_matrix", false, false);
	m_bUseViewProjectionMatrix		= _node.GetBoolProperty("use_view_projection_matrix", false, false);
	m_uUseTextures					= _node.GetIntProperty("use_textures", 0, false);

	GetTechniqueByEffect();
	CreateInputsLayouts();
}

//-------------------------------------------------
CEffectTechnique::~CEffectTechnique()
{
	for(uint32 i=0; i<m_InputLayoutVector.size(); ++i)
	{
		CHECKED_RELEASE(m_InputLayoutVector[i]);
	}
	m_InputLayoutVector.clear();
	m_InputLayoutMap.clear();
}

//-------------------------------------------------
const std::string& CEffectTechnique::GetTechniqueName() const
{
	return m_sTechniqueName;
}

//-------------------------------------------------
void CEffectTechnique::GetTechniqueByEffect()
{
	m_pTechnique = m_pEffect->GetTechniqueByName(m_sTechniqueName);
	assert(m_pTechnique && m_pTechnique->IsValid());
}

//-------------------------------------------------
void CEffectTechnique::CreateInputsLayouts()
{
	D3DX11_TECHNIQUE_DESC desc;
	m_pTechnique->GetDesc(&desc);

	for(uint8 i=0; i<desc.Passes; ++i)
	{
		ID3DX11EffectPass* l_pPass = m_pTechnique->GetPassByIndex(i);

		D3DX11_PASS_SHADER_DESC effectVsDesc;
		D3DX11_EFFECT_SHADER_DESC effectVsDesc2;

		l_pPass->GetVertexShaderDesc(&effectVsDesc);		
		effectVsDesc.pShaderVariable->GetShaderDesc(effectVsDesc.ShaderIndex, &effectVsDesc2);

		ID3D11InputLayout *l_InputLayout;
		D3D11_INPUT_ELEMENT_DESC inputDesc[] =
		{
			{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
			//{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
			 { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		};
		
		HRESULT hr = RENDER_MANAGER->GetDevice()->CreateInputLayout(
			inputDesc, ARRAYSIZE(inputDesc), effectVsDesc2.pBytecode, effectVsDesc2.BytecodeLength, &l_InputLayout);

		assert(SUCCEEDED(hr));

		m_InputLayoutMap[l_pPass] = l_InputLayout;
		m_InputLayoutVector.push_back(l_InputLayout);
	}
}

//-------------------------------------------------
ID3D11InputLayout* CEffectTechnique::GetInputLayout(ID3DX11EffectPass* _pass)
{
	return m_InputLayoutMap[_pass];
}

//-------------------------------------------------
void CEffectTechnique::BeginRender()
{
	CEffectManager* l_pEffectManager = RENDER_MANAGER->GetEffectManager();

	RENDER_MANAGER->GetDeviceContext()->IASetInputLayout(m_InputLayoutVector[0]);
	HRESULT hr = S_OK;

	if(m_bUseWorldMatrix)
		hr = static_cast<ID3DX11EffectMatrixVariable*>(m_pEffect->GetWorldMatrixParameter())->SetMatrix((float*)&l_pEffectManager->GetWorldMatrix().GetXMMatrix());

	assert(SUCCEEDED(hr));
	if(m_bUseViewMatrix)
		hr = static_cast<ID3DX11EffectMatrixVariable*>(m_pEffect->GetViewMatrixParameter())->SetMatrix((float*)&l_pEffectManager->GetViewMatrix().GetXMMatrix());

	assert(SUCCEEDED(hr));
	if(m_bUse2DViewMatrix)
		hr = static_cast<ID3DX11EffectMatrixVariable*>(m_pEffect->Get2DViewMatrixParameter())->SetMatrix((float*)&l_pEffectManager->Get2DViewMatrix().GetXMMatrix());

	assert(SUCCEEDED(hr));
	if(m_bUseProjectionMatrix)
		hr = static_cast<ID3DX11EffectMatrixVariable*>(m_pEffect->GetProjectionMatrixParameter())->SetMatrix((float*)&l_pEffectManager->GetProjectionMatrix().GetXMMatrix());

	assert(SUCCEEDED(hr));
	if(m_bUseOrthographicMatrix)
		hr = static_cast<ID3DX11EffectMatrixVariable*>(m_pEffect->GetOrthographicMatrixParameter())->SetMatrix((float*)&l_pEffectManager->GetOrthographicMatrix().GetXMMatrix());

	assert(SUCCEEDED(hr));
	if(m_bUseViewProjectionMatrix)
		static_cast<ID3DX11EffectMatrixVariable*>(m_pEffect->GetViewProjectionMatrixParameter())->SetMatrix((float*)&l_pEffectManager->GetViewProjectionMatrix().GetXMMatrix());

	if(m_uUseTextures > 0)
	{
		for(uint8 i=0; i<m_uUseTextures; ++i)
		{
			static_cast<ID3DX11EffectShaderResourceVariable*>(m_pEffect->GetTextureParameter(i))->SetResource(l_pEffectManager->GetTexture()->GetShaderResource());
		}
	}

	assert(SUCCEEDED(hr));
}